
#include "kodes.h"
#include "local8.h"
#include "latin3.h"
#include "utf16.h"
#include "utf8.h"
#include "xsystem.h"
#include "hsystem.h"
#include <boost/assert.hpp>
#include <boost/scoped_ptr.hpp>
#include <fstream>
#include <sstream>


const char *SignaroNomoj[] =
{
  "UTF8",
  "UTF16",
  "LATIN3",
  "X_SYS",
  "X_SYS_UTF8",
  "X_SYS_UTF16",
  "H_SYS",
  "H_SYS_UTF8",
  "H_SYS_UTF16",
  "LOCAL"
};

static_assert(S_LAST == sizeof(SignaroNomoj)/sizeof(*SignaroNomoj), "Sigraro kaj SignaroNomoj devas havi egala grandojn");

LegoKonverto::LegoKonverto()
  : is_(nullptr), errorChar_(0)
{
}

// Legi tuta
void LegoKonverto::doni(wstring &frukto)
{
  wostringstream oss;
  for (;;)
  {
    wchar_t c = doni();
    if (!c)
      break;
    oss << c;
  }

  frukto.swap(oss.str());
}

float LegoKonverto::progreso() const 
{
  return 0; 
}

void LegoKonverto::setStream(istream *s)
{
  BOOST_ASSERT(s);
  BOOST_ASSERT(0 == s->tellg());
  if (!s || !s->good())
    throw runtime_error("Can not read data");

  is_ = s;
  waitBOM_ = true;
}

LegoKonverto *LegoKonverto::getBySignaro(Signaro sig)
{
  switch (sig)
  {
  case S_UTF16:        return new ElUtf16();
  case S_UTF8 :        return new ElUtf8();
  case S_LATIN3:       return new ElLatin3();
  case S_X_SYS:        return new ElXSys(S_LOCAL);
  case S_X_SYS_UTF8:   return new ElXSys(S_UTF8);
  case S_X_SYS_UTF16:  return new ElXSys(S_UTF16);
  case S_H_SYS:        return new ElHSys(S_LOCAL);
  case S_H_SYS_UTF8:   return new ElHSys(S_UTF8);
  case S_H_SYS_UTF16:  return new ElHSys(S_UTF16);
  case S_LOCAL:        return new ElLocal8();
  }
  BOOST_ASSERT(false);
  return nullptr;
}

LegoKonverto *LegoKonverto::autoDifiniSignaro(istream *s)
{
  return nullptr;
}


unsigned char LegoKonverto::doniBajton()
{
  BOOST_ASSERT(is_);
  if (is_->eof())
    return 0;
  
  char b;
  is_->read(&b, 1);
  if (is_->fail())
    return 0;

  return b;
}

ScriboKonverto::ScriboKonverto()
  : os_(nullptr), wrBOM_(false)
{
}


void ScriboKonverto::setStream(ostream *s)
{
  BOOST_ASSERT(s);
  BOOST_ASSERT(0 == s->tellp());
  if (!s || !s->good())
    throw runtime_error("Can not write data");

  os_ = s;
}

void ScriboKonverto::writeBom(bool wb)
{
  BOOST_ASSERT(!os_);
  wrBOM_ = wb;
}

void ScriboKonverto::meti(const wstring &fonto)
{
  for (auto it=fonto.begin(); it!=fonto.end(); ++it)
    meti(*it);
}

ScriboKonverto *ScriboKonverto::getBySignaro(Signaro sig)
{
  switch (sig)
  {
  case S_UTF16:        return new AlUtf16();
  case S_UTF8 :        return new AlUtf8();
  case S_LATIN3:       return new AlLatin3();
  case S_X_SYS:        return new AlXSys(S_LOCAL);
  case S_X_SYS_UTF8:   return new AlXSys(S_UTF8);
  case S_X_SYS_UTF16:  return new AlXSys(S_UTF16);
  case S_H_SYS:        return new AlHSys(S_LOCAL);
  case S_H_SYS_UTF8:   return new AlHSys(S_UTF8);
  case S_H_SYS_UTF16:  return new AlHSys(S_UTF16);
  case S_LOCAL:        return new AlLocal8();
  }
  BOOST_ASSERT(false);
  return nullptr;
}

void ScriboKonverto::metiBajton(unsigned char b)
{
  BOOST_ASSERT(os_);
  os_->write((char*)&b, 1);
}

//BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID lpReserved)
int __stdcall DllMain(void* hModule, unsigned long reason, void* lpReserved)
{
  return 1;
}
